﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
using Flatland.GeneticProgramming.CoreTypes;
using Flatland.Utilities;
using Microsoft.Xna.Framework.Graphics;

/**
* 
* Copyright (c) 2012 Anders Høst Kjærgaard | ahkj@itu.dk
* 
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, 
* including without limitation the rights to use, copy, modify, merge, publish, distribute, 
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Flatland.GeneBank {
    /// <summary>
    /// SkinTexture holds the Primitive material that becomes a skin texture
    /// </summary>
    [Serializable]
    public class SkinTexture : GenoType, IExpression<Bitmap> {
        [Primitive]
        public Bitmap _bitMap = new Bitmap(64, 64);

        private bool calcDone;

        protected override void Act(ref string msg) {
            if (!calcDone) {
                string[] filenames = Directory.GetFileSystemEntries(Directory.GetCurrentDirectory() + "\\MyTextures");
                List<String> validNames = new List<String>(filenames.Length);
                string file = string.Empty;
                for (int i = 0; i < filenames.Length; i++) {
                    if (filenames[i].Contains(".png")) {
                        validNames.Add(filenames[i]);
                    }
                }
                //Use a random .png
                if (0 < validNames.Count) {
                    _bitMap = new Bitmap(validNames[Utils.Random.Next(validNames.Count)]);
                }
                //Add gene manipulation
                //_bitMap = (Bitmap) Execute();
                //Set new Texture material on the Agent
                Agent.TextureMaterial = BitmapToTexture2D(Program.FlatlandWorld.GraphicsDevice, _bitMap);
                Agent.UpdateShape(Agent.Vertices(), Agent.Color, Agent.Size);
                calcDone = true;
            }
        }

        /// <summary>
        /// Increases the color value of a 3x3 area
        /// </summary>
        /// <param name="bm"></param>
        /// <returns></returns>
        [Primitive]
        public Bitmap Dotter(Bitmap bm, Bitmap bm2) {
            //50% chance of ignore
            if (Utils.Random.Next(2) == 1) return bm;

            int x = (Utils.Random.Next(bm.Width - 4) + 2);
            int y = (Utils.Random.Next(bm.Height - 4) + 2);
            //Centre
            //others 
            for (int i = -1; i < 2; i++) {
                for (int j = -1; j < 2; j++) {
                    Color col = bm.GetPixel(x + i, y + j);
                    Color blend = bm2.GetPixel(x + i, y + j);
                    if (i == 0 && j == 0)
                        bm.SetPixel(x + i, y + j, Color.FromArgb((col.A + 15 + blend.A) % 256, (col.R + 25 + blend.R) % 256, (col.G + 25 + blend.G) % 256, (col.B + 25 + blend.B) % 256));
                    else
                        bm.SetPixel(x + i, y + j, Color.FromArgb((col.A + 10 + blend.A) % 256, (col.R + 15 + blend.R) % 256, (col.G + 15 + blend.G) % 256, (col.B + 15 + blend.B) % 256));
                }
            }
            return bm;
        }

        /// <summary>
        /// Converts bitmap to Texture2D
        /// Snippet from http://forums.create.msdn.com/forums/p/3051/15056.aspx
        /// </summary>
        /// <param name="GraphicsDevice"></param>
        /// <param name="image"></param>
        /// <returns></returns>
        public static Texture2D BitmapToTexture2D(GraphicsDevice GraphicsDevice, Bitmap image) {
            // Buffer size is size of color array multiplied by 4 because   
            // each pixel has four color bytes  
            int bufferSize = image.Height * image.Width * 4;

            // Create new memory stream and save image to stream so   
            // we don't have to save and read file  
            MemoryStream memoryStream = new MemoryStream(bufferSize);
            image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);

            // Creates a texture from IO.Stream - our memory stream  
            Texture2D texture = Texture2D.FromStream(GraphicsDevice, memoryStream);
            return texture;
        }

        public SkinTexture(SerializationInfo info, StreamingContext context) {
            //ignore this if nothing should be serialized
        }

        public SkinTexture() {}

        public override double Fitness()
        {
            return 0;
        }

        public override object Clone() {
            return new SkinTexture();
        }
    }
}